﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Flagwind.ComponentModel;
using Flagwind.ComponentModel.DataAnnotations;
using Flagwind.Security;
using Flagwind.Common;

namespace Flagwind.ComponentModel
{
	/// <summary>
	/// 表示数据传输请求命令。
	/// </summary>
	public class RequestInstruction<T> : IRequestInstruction where T : DataObject, new()
	{
		#region 公共属性

		/// <summary>
		/// 获取或设置当前请求签名。
		/// </summary>
		public string Sign
		{
			get;
			set;
		}

		/// <summary>
		/// 获取或设置合作者ID。
		/// </summary>
		public string PartnerId
		{
			get;
			set;
		}

		/// <summary>
		/// 获取或设置当前请求时间戳。
		/// </summary>
		public long Timestamp
		{
			get;
			set;
		}

		/// <summary>
		/// 获取或设置安全凭证号。
		/// </summary>
		public string Credential
		{
			get;
			set;
		}

		/// <summary>
		/// 获取或设置请求参数。
		/// </summary>
		[RequiredValidator(ErrorMessage = "Text.Request.MissingArgument")]
		[RequiredValidator(RuleName = "required", ErrorMessage = "Text.Request.MissingArgument")]
		public T Params
		{
			get;
			set;
		}

		/// <summary>
		/// 表示当前请求是否为有效请求。
		/// </summary>
		public bool IsAvailable
		{
			get
			{
				return !this.ValidationErrors.Any();
			}
		}

		/// <summary>
		/// 获取在解析请求中生成的错误集合。
		/// </summary>
		public IEnumerable<ValidationResult> ValidationErrors
		{
			get
			{
				var context = new ValidationContext(this);

				return this.Validate(context);
			}
		}

		#endregion

		#region 构造方法

		/// <summary>
		/// 初始化 RequestInstruction 类的新实例。
		/// </summary>
		public RequestInstruction()
		{

		}

		/// <summary>
		/// 初始化 RequestInstruction 类的新实例。
		/// </summary>
		/// <param name="sign">签名。</param>
		/// <param name="partnerId">合作者ID。</param>
		/// <param name="timestamp">时间戳。</param>
		public RequestInstruction(string sign, string partnerId, long timestamp) : this(sign, partnerId, null, timestamp)
		{

		}

		/// <summary>
		/// 初始化 RequestInstruction 类的新实例。
		/// </summary>
		/// <param name="sign">签名。</param>
		/// <param name="partnerId">合作者ID。</param>
		/// <param name="credential">安全凭证号。</param>
		/// <param name="timestamp">时间戳。</param>
		public RequestInstruction(string sign, string partnerId, string credential, long timestamp)
		{
			this.Sign = sign;
			this.Params = new T();
			this.PartnerId = partnerId;
			this.Credential = credential;
			this.Timestamp = timestamp;
		}

		#endregion

		#region 验证实现

		public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
		{
			var request = validationContext.ObjectInstance as RequestInstruction<T>;

			if(request == null)
				throw new InvalidOperationException();

			var result = new List<ValidationResult>();

			if(this.Params != null)
			{
				var type = request.Params.GetType();

				// 获取签名验证标签
				var attributes = type.GetCustomAttributes(typeof(SignAttribute), false).OfType<SignAttribute>().FirstOrDefault();

				// 存在标签，进行签名认证
				if(attributes != null)
				{
					// 验证签名是否有效。
					var dic = this.Params.ToDictionary();
					var sign = new Signature(dic, this.PartnerId, this.Timestamp);
					var checkSkin = sign.CheckSign(this.Sign);

					if(!checkSkin)
						result.Add(new ValidationResult("签名计算错误。", new[] { "Sign" }));
				}

				// 追加参数验证错误。
				result.AddRange(this.Params.GetValidationErrors());
			}

			// 返回验证结果。
			return result;
		}

		#endregion
	}
}
